/**
    Copyright (C) 2012 Guido Ludwig

    This file is part of JATT.
	http://code.google.com/p/jatt/

    JATT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.guidoludwig.jatt.util;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.sanselan.ImageFormat;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.Sanselan;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.CannotWriteException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldDataInvalidException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.images.Artwork;
import org.jaudiotagger.tag.images.StandardArtwork;

import de.guidoludwig.jatt.JATT;

public class AudioInfo {

	private final File file;
	private final AudioFile audioFile;
	private final Tag tag;
	private BufferedImage image;
	private byte[] binaryImage;

	public AudioInfo(File file) throws CannotReadException, IOException,
			TagException, ReadOnlyFileException, InvalidAudioFrameException {
		this.file = file;
		audioFile = AudioFileIO.read(file);
		tag = audioFile.getTag();
		getImageFromTag();
	}

	public File getFile() {
		return file;
	}

	public AudioFile getAudioFile() {
		return audioFile;
	}

	public Tag getTag() {
		return tag;
	}

	public boolean isArtworkTagged() {
		return image != null;
	}

	public boolean isArtistAndAlbumTagged() {
		return isArtistTagged() && isAlbumTagged();
	}
	public boolean isArtistTagged() {
		return getArtist() != null && getArtist().length() > 0;
	}
	public boolean isAlbumTagged() {
		return getAlbum() != null && getAlbum().length() > 0;
	}

	public BufferedImage getImage() {
		return image;
	}

	public byte[] getBinaryImage() {
		return binaryImage;
	}

	public String getArtist() {
		return tag == null ? null : tag.getFirst(FieldKey.ARTIST);
	}

	public String getAlbum() {
		return tag == null ? null : tag.getFirst(FieldKey.ALBUM);
	}

	public boolean deleteArtwork() throws IOException,
			FieldDataInvalidException, CannotWriteException {
		if (tag != null) {
			tag.deleteArtworkField();
			audioFile.setTag(tag);
			audioFile.commit();
		}
		image = null;
		binaryImage = null;
		return true;
	}

	public boolean tagFile(File imageFile) throws IOException,
			FieldDataInvalidException, CannotWriteException {

		if (imageFile == null) {
			throw new IllegalArgumentException(
					"Image for Tagging must not be null");
		}
		Artwork art = new StandardArtwork();
		art.setFromFile(imageFile);
		tag.setField(art);
		audioFile.setTag(tag);
		audioFile.commit();
		getImageFromTag();
		return true;
	}

	private void getImageFromTag() throws IOException {
		image = null;
		binaryImage = null;
		if (tag != null) {
			List<Artwork> art = tag.getArtworkList();
			if (art != null) {
				for (Artwork img : art) {
					if (img.getBinaryData() != null) {
						binaryImage = img.getBinaryData();
						image = (BufferedImage) img.getImage();
					}
				}
			}
		}
	}

	public File writeImageToFile(File directory, String baseFileName, boolean overwriteIfExists)
			throws IOException, UnsupportedOperationException,
			ImageReadException, ImageWriteException {
		if (!isArtworkTagged()) {
			throw new UnsupportedOperationException(
					"Cant write image to file - untagged !");
		}
		ImageFormat format = Sanselan.guessFormat(getBinaryImage());
		if (format == null) {
			throw new UnsupportedOperationException(
					"Cant write image to file - null image format !");
		}
		String xtension = ImageFormat.IMAGE_FORMAT_JPEG.equals(format) ? "jpg"
				: format.extension.toLowerCase();
		String newfilename = baseFileName + "." + xtension;
		File outpFile = new File(directory, newfilename);
		if (!overwriteIfExists && outpFile.exists()) {
			return null;
		}
		if (ImageFormat.IMAGE_FORMAT_JPEG.equals(format)) {
			xtension = "jpg";
			// Sanselan does not support writing jpg
			ImageIO.write(getImage(), xtension, outpFile);
		} else {
			Sanselan.writeImage(getImage(), outpFile, format, null);
		}
		JATT.debug("Image written to " + outpFile.getAbsolutePath());
		return outpFile;
	}

}